package com.example;

import com.example.entity.*;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * 将一个对象的引用变量直接赋值给另一个引用变量，就是让两个变量共享指向同一个对象的引用，属于引用传递，不会创建新对象，也不会克隆。
 * 引用赋值 vs 浅克隆 vs 深克隆
 * 操作方式	                是否新对象	引用字段是否独立	    说明
 * 引用赋值 p2 = p1	        ❌ 否	    ❌ 完全共享	        只是多了一个名字指向原对象
 * 浅克隆 p2 = p1.clone()	✅ 是	    ❌ 引用字段共享	    只复制一层引用地址
 * 深克隆	                ✅ 是	    ✅ 所有字段独立	    每层引用都复制
 * 只有 new、clone()、序列化、或者拷贝构造方法才会创建新对象；赋值操作本质上只是“共享引用”，不会创建新对象。
 */
@SpringBootTest
public class ShallowAndDeepClone {

    /**
     * 浅克隆创建的是“新对象”，但“内容中有共享”；深克隆创建的是“全新副本”，内容完全独立。
     */
    @Test
    public void shallowClone() throws CloneNotSupportedException {

        /**
         * 浅克隆只复制对象本身（基本类型值 + 对象引用地址），不复制引用对象的内容。
         * 即：
         * 基本数据类型（int, double等）会被复制。
         * 引用类型（如数组、类对象）只复制引用地址，原始对象和克隆对象共享这些引用。
         * person:com.example.entity.Person@4b9c411
         * clone:com.example.entity.Person@41e9f86
         * ✅ 浅克隆是：两个不同的引用变量指向不同的对象本体，但其中的“引用字段”仍然指向相同的子对象
         */
        Address address = new Address("shanghai");
        Person person = new Person("Tom", 20, address);
        System.out.println("person:" + person);
        Person clone = (Person) person.clone();
        System.out.println("clone:" + clone);

        /**
         * person.address:com.example.entity.Address@19b75b2b
         * clone.address:com.example.entity.Address@19b75b2b
         */
        System.out.println("person.address:" + person.address);
        System.out.println("clone.address:" + clone.address);

        /**
         * 可变引用对象：区别最大！
         * 浅克隆：clone.address 和 original.address 是 同一个对象地址 → ❌ 改变一个会影响另一个；
         * 深克隆：使用 clone.address = (Address) address.clone(); → ✅ 两个对象独立。
         */
        System.out.println("person.address.city:" + person.address.city);
        clone.address.city = "beijing";
        // 输出 beijing，因为是浅克隆，共享引用
        System.out.println("person.address.city:" + person.address.city);
        System.out.println("clone.address.city:" + clone.address.city);

        /**
         *  不可变对象：通常浅克隆也安全
         *  Java 中的 String 是不可变的（immutable），无法通过引用改变它的内容；
         * 所以即使浅克隆只是复制了引用地址，也 不会互相影响；
         * ✅ 通常浅克隆足够安全（无需深克隆）
         */
        clone.name = "Jack";
        System.out.println("person.name:" + person.name);
        System.out.println("clone.name:" + clone.name);

        /**
         * 基本类型：无论浅深克隆都没问题
         * 无论浅克隆还是深克隆，都是 值复制；
         * 改 clone.age 不影响 person.age；
         * ✅ 安全！
         */
        clone.age = 18;
        System.out.println("person.age:" + person.age);
        System.out.println("clone.age:" + clone.age);

        // false，不是同一个对象
        System.out.println(person == clone);
        // true，共享引用字段
        System.out.println(person.address == clone.address);

    }

    /**
     * 浅克隆会复制对象的基本数据类型和不可变对象字段的值或引用，但对于引用类型字段，只复制其引用地址，不复制其所指向的对象本身；
     * 而深克隆不仅复制基本类型和不可变对象，还会递归地复制所有引用对象，确保克隆对象在所有层级上与原对象完全独立。
     * 对于浅克隆：
     * ✔️ 会复制基本数据类型字段（值复制）；
     * ✔️ 会复制不可变对象的引用（如 String）；
     * ❗ 但对于引用类型字段（如 Address, List），只是复制引用地址，不复制其内容；
     * 🔁 所以：浅克隆对象与原对象之间的引用字段仍然共享同一个子对象，修改其中一个会影响另一个。
     * 对于深克隆：
     * ✔️ 同样复制基本类型字段和值；
     * ✔️ 复制不可变对象的引用（因其内容不可变，安全）；
     * ✔️ 对于引用类型字段，会递归地调用 clone() 方法，把引用对象也复制一份；
     * 🔁 这样原对象和克隆对象中的所有字段都独立，不会互相影响，实现了真正的深度独立复制。
     */
    @Test
    public void deepClone() throws CloneNotSupportedException {

        /**
         * 深克隆不仅复制对象本身，还会递归复制所有引用对象的内容，使新对象与原对象完全独立。
         * animal:com.example.entity.Animal@26c77f54
         * clone:com.example.entity.Animal@3e856100
         */
        Master master = new Master("Tom");
        Animal animal = new Animal("Dog", 3, master);
        System.out.println("animal:" + animal);
        Animal clone = (Animal) animal.clone();
        System.out.println("clone:" + clone);

        /**
         * animal.master:com.example.entity.Master@233f52f8
         * clone.master:com.example.entity.Master@69ec93c2
         */
        System.out.println("animal.master:" + animal.master);
        System.out.println("clone.master:" + clone.master);

        /**
         * 可变引用对象
         */
        clone.master.name = "Jack";
        System.out.println("animal.master.name:" + animal.master.name);
        System.out.println("clone.master.name:" + clone.master.name);

        /**
         * 不可变对象
         */
        clone.name = "BigDog";
        System.out.println("animal.name:" + animal.name);
        System.out.println("clone.name:" + clone.name);

        /**
         * 基本类型
         */
        clone.age = 8;
        System.out.println("animal.age:" + animal.age);
        System.out.println("clone.age:" + clone.age);

        // false，不是同一个对象
        System.out.println(animal == clone);
        // false，引用字段也不同
        System.out.println(animal.master == clone.master);

    }

    @Test
    public void bigDeepClone() throws CloneNotSupportedException {
        /**
         * bigAnimal:com.example.entity.BigAnimal@3e856100
         * clone:com.example.entity.BigAnimal@6e9a0bea
         */
        Master master = new Master("Tom");
        BigAnimal bigAnimal = new BigAnimal("Dog", 3, master);
        /**
         * 浅克隆
         * 未克隆可变引用对象
         */
        BigAnimal clone = (BigAnimal) bigAnimal.clone();
        System.out.println("bigAnimal:" + bigAnimal);
        System.out.println("clone:" + clone);
        /**
         * bigAnimal.master:com.example.entity.Master@28fc1132
         * clone.master:com.example.entity.Master@28fc1132
         */
        System.out.println("bigAnimal.master:" + bigAnimal.master);
        System.out.println("clone.master:" + clone.master);

        /**
         * 深克隆
         * 克隆了可变引用对象
         */
        BigAnimal cloneBigAnimal = (BigAnimal) bigAnimal.clone();
        cloneBigAnimal.master = (Master) master.clone();
        /**
         * cloneBigAnimal:com.example.entity.BigAnimal@19fec3d6
         * cloneBigAnimal.master:com.example.entity.Master@5287ba5f
         */
        System.out.println("cloneBigAnimal:" + cloneBigAnimal);
        System.out.println("cloneBigAnimal.master:" + cloneBigAnimal.master);

        /**
         * 可变引用对象
         */
        System.out.println("bigAnimal.master.name:" + bigAnimal.master.name);
        System.out.println("cloneBigAnimal.master.name:" + cloneBigAnimal.master.name);
        cloneBigAnimal.master.name = "Jack";
        System.out.println("bigAnimal.master.name:" + bigAnimal.master.name);
        System.out.println("cloneBigAnimal.master.name:" + cloneBigAnimal.master.name);

        /**
         * 不可变对象
         */
        System.out.println("bigAnimal.name:" + bigAnimal.name);
        System.out.println("cloneBigAnimal.name:" + cloneBigAnimal.name);
        cloneBigAnimal.name = "BigDog";
        System.out.println("bigAnimal.name:" + bigAnimal.name);
        System.out.println("cloneBigAnimal.name:" + cloneBigAnimal.name);

        /**
         * 基本类型
         */
        System.out.println("bigAnimal.age:" + bigAnimal.age);
        System.out.println("cloneBigAnimal.age:" + cloneBigAnimal.age);
        cloneBigAnimal.age = 18;
        System.out.println("bigAnimal.age:" + bigAnimal.age);
        System.out.println("cloneBigAnimal.age:" + cloneBigAnimal.age);

    }

}
